Introduzione

Questo progetto usa i servizi offerti da FMP per reperire dati finanziari dei principali indici, titoli e indicatori delle borse più importanti del mondo. Oltre a reperire questi dati, li usa per ottenere analisi, processare i risultati e produrre indicatori usati in diversi ambiti come l’analisi finanziario, la valuation e l’analisi del rischio.

Il progetto è stato scritto nel linguaggio R ma può essere portato a qualsiasi linguaggio di programmazione con le dovute modifiche. Oltre a ciò, è stato anche complementato da annotazioni che possono essere utili alla valutazione di base del codice ed eventuali chiarimenti su passaggi non chiari per gli studenti ancora in preparazione.

Il provider è Financial Modeling Prep e tutti possono ottenere una key gratuita registrandosi al sito.

Setting iniziale

L’idea alla base del codice è usare i servizi offerti dall’API del sito per trovare dati finanziari da utilizzare nell’analisi o valutazione finanziaria. Attraverso questo script è possibile richiedere anche le metriche e analisi dei dati ricevuti, in modo da poter confrontarle con eventuali analisi già fatti con metodi tradizionali.

ask_api_key <- function() 
  {
  key <- Sys.getenv("FMP_API_KEY")
  if (key == "") 
    {
    if (!exists("global_api_key")) 
      {
      global_api_key <<- readline(" Inserisci la tua API Key: ")
      Sys.setenv(FMP_API_KEY = global_api_key) 
    }
    return(global_api_key)
  }
  return(key)
}

Questo script ci permette di creare una funzione che permette di fissare la key con cui faremo le chiamate ed otterremo i risultati richiesti. Il sys.getenv permette di fissare a livello globale questa key. Il doppio condizionale if ci permette di andare a chiedere, ogni volta che qualche script richiederà l’uso della key, se abbiamo già disponibile una key di sistema fissata. Se non esiste, allora la funzione richiederà all’usuario di settare una API key attraverso l’uso della funzione readline e il sys.setenv per fissarla a livello environment.

FMP_CALL <- function(endpoint) 
  {
  api_key <- ask_api_key()
  url <- paste0("https://financialmodelingprep.com/api/v3/", endpoint, "?apikey=", api_key)
  res <- httr::GET(url)
  if (res$status_code == 200) 
    {
    content <- httr::content(res, as = "text")
    data <- fromJSON(content)
    return(data)
  } 
  else 
    {
    message(" Errore API: ", res$status_code)
    return(NULL)
  }
}

Avendo settato la key dell’usuario, questa funzione richiede di dare come input cosa si vuole avere dalla chiamata (es: key-metrics/META , profile/AAPL). Il condizionale if serve alla gestione di eventuali errori. Se la chiamata provoca una situazione diversa a code: 200, la funzione avvertirà di un generico errore che avrà bisogno di verifiche da parte dell’usuario.

La richiesta dovrà essere formulata attraverso la funzione “FMP_CALL”, l’input della funzione sarà il codice richiesta (“profile/GOOGL”)

Applicazione 1: FX exchanges prices.

head(FMP_CALL("fx"),10)
##     ticker     bid     ask    open     low     high       changes
## 1  AED/AUD 0.43132 0.43232 0.42961 0.42961  0.43273  0.0030041000
## 2  AED/BHD 0.10256 0.10269 0.10256 0.10238  0.10269 -0.0001750619
## 3  AED/CAD 0.39222 0.39222  0.3888  0.3888  0.39235  0.0032783900
## 4  AED/CHF 0.23909 0.24009 0.24015 0.23909  0.24015 -0.0002545666
## 5  AED/DKK 1.87294 1.87529 1.87294 1.86421  1.88249 -0.0069382300
## 6  AED/EUR  0.2511  0.2516 0.25219 0.25045  0.25227 -0.0006644876
## 7  AED/GBP 0.21018 0.21118 0.21097 0.21018  0.21103 -0.0007600000
## 8  AED/ILS 0.98855 0.98855 0.98855 0.98253  1.03584  0.0043467200
## 9  AED/INR  23.659  23.759  23.653  23.653 23.73775  0.0563705100
## 10 AED/JOD 0.19328 0.19328 0.19328 0.19277  0.19362 -0.0002205977
##                   date
## 1  2025-03-09 13:35:50
## 2  2025-03-09 13:35:50
## 3  2025-03-09 13:35:50
## 4  2025-03-09 13:35:50
## 5  2025-03-09 13:35:50
## 6  2025-03-09 13:35:50
## 7  2025-03-09 13:35:50
## 8  2025-03-09 13:35:50
## 9  2025-03-09 13:35:50
## 10 2025-03-09 13:35:50

Attraverso la richiesta “fx” posso richiedere i prezzi in tempo reale delle principali currencies. L’head viene usato per avere una visione più compressa dell’esempio, richiedendo solo le prime 10 valute scambiate. La lista è ovviamente più ampia.

Ovviamente questi dati possono essere salvati nel nostro environment per poter succesivamente essere usati con altre formule o per altri scopi.

Applicazione 2: Sorprese di GOOGL

GOOGL_SURPRISES<- FMP_CALL("earnings-surprises/GOOGL")

head(GOOGL_SURPRISES,10)
##          date symbol actualEarningResult estimatedEarning
## 1  2025-02-04  GOOGL                2.15             2.12
## 2  2024-10-29  GOOGL                2.12             1.83
## 3  2024-07-23  GOOGL                1.89             1.84
## 4  2024-04-25  GOOGL                1.89             1.51
## 5  2024-01-30  GOOGL                1.64             1.59
## 6  2023-10-24  GOOGL                1.55             1.45
## 7  2023-07-25  GOOGL                1.44             1.34
## 8  2023-04-25  GOOGL                1.17             1.07
## 9  2023-02-02  GOOGL                1.05             1.18
## 10 2022-10-25  GOOGL                1.06             1.25
df<- as.data.frame(GOOGL_SURPRISES)
df$date <- as.numeric(as.POSIXct(df$date))

plot_ly(df, x = ~actualEarningResult, y = ~estimatedEarning, z = ~date, 
        type = "scatter3d", mode = "markers", marker = list(size = 5, color = df$actualEarningResult, colorscale = "Viridis")) %>%
  layout(title = "GOOGL SURPRISES",
         scene = list(
           xaxis = list(title = "Actual"),
           yaxis = list(title = "Estimated"),
           zaxis = list(title = "Date")
         ))

Attraverso la richiesta “earnings-surprises/GOOGL” otteniamo data sulle differenze fra previsioni e actual delle earnings di Google. Salvandole nel nostro environment possiamo poi facilmente maneggiarle per, ad esempio, farne un grafico che migliori la visione e valutazione di questi dati

Applicazione 3 : Discounted Cash Flow

Il Discounted Cash Flow (DCF) è uno dei metodi di valutazione finanziaria più conosciuti nell’industria. Esso permette di rapportare il valore attuale dell’impresa alle sue previsioni future, permettendo una valutazione più ampia e che tiene conto degli sviluppi futuri ed annessi guadagni.

Il DCF si calcola come:

\[DCF = \sum_{t=1}^{n} \frac{FCF_t}{(1 + WACC)^t} + \frac{TV}{(1 + WACC)^n}\]

La sommatoria contiene al suo interno altri valori che devono essere scorporati in diverse componenti:

1.Free Cash Flow (FCF)

\[ FCF = EBIT \times (1 - T) + D\&A - CAPEX - \Delta NWC \]

2.Weighted Average Cost of Capital (WACC)

\[ WACC = \frac{E}{V} r_E + \frac{D}{V} r_D (1 - T) \]

3.Terminal Value (TV)

\[ TV = \frac{FCF_{n} \times (1 + g)}{WACC - g} \]

Avendo a mente i valori da trovare, possiamo cominciare a richiedere i dati tramite la funzione scritta

1.Free Cash Flow

CFS_data <- FMP_CALL("cash-flow-statement/MSFT")
fcf <- CFS_data$freeCashFlow
print(fcf)
## [1] 7.4071e+10 5.9475e+10 6.5149e+10 5.6118e+10 4.5234e+10

Richiediamo gli ultimi 5 Cash Flow Statement dell’impresa attraverso la funzione “cash-flow-statement/****” e da essa scorporiamo il free cash flow, che è il primo valore di cui avremo bisogno per calcolare il nostro DCF.

2.Weighted Average Cost of Capital

key_metrics <- FMP_CALL("key-metrics/MSFT")
Fin_stat<- FMP_CALL("financial-statement-full-as-reported/MSFT")
sheets<-FMP_CALL("balance-sheet-statement/MSFT")
df<- cbind(key_metrics,Fin_stat,sheets)

beta <- 0.94
Rf <- 0.04   
Rm_minus_Rf <- 0.05 
tax_rate <- 0.21

Re <-c(Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf,Rf + beta * Rm_minus_Rf)
Rd <- df$interestexpense / df$totalDebt  
interest_expense <- df$interestexpense
total_debt <- df$totalDebt  
cash <- df$cashAndCashEquivalents  

D <- total_debt - cash  
E <- key_metrics$marketCap 

Ve <- E + D  
We <- E / Ve  
Wd <- D / Ve  

MSFT_WACC <- We * Re + Wd * Rd * (1 - tax_rate)

Anno <- c(2024, 2023, 2022, 2021, 2020)

df_MSFT_WACC <- data.frame(
  Anno = Anno,
  Costo_Capitale_Proprio = Re,
  Costo_Debito = Rd,
  Debito_Netto = D,
  Peso_Equity = We,
  Peso_Debito = Wd,
  WACC = MSFT_WACC
)

print(df_MSFT_WACC)
##   Anno Costo_Capitale_Proprio Costo_Debito Debito_Netto Peso_Equity Peso_Debito
## 1 2024                  0.087   0.04372309   4.8812e+10   0.9858219 0.014178107
## 2 2023                  0.087   0.03281914   2.5261e+10   0.9901360 0.009864026
## 3 2022                  0.087   0.03367064   4.7339e+10   0.9760010 0.023999047
## 4 2021                  0.087   0.03963113   5.3551e+10   0.9744756 0.025524380
## 5 2020                  0.087   0.03849404   5.7422e+10   0.9642483 0.035751707
##         WACC
## 1 0.08625623
## 2 0.08639758
## 3 0.08555045
## 4 0.08557851
## 5 0.08497682

Richiediamo il file “metrics”, i financial statements e i balance sheets dalla database di FMI e li salviamo in un unico dataframe che ci servirà per il calcolo del nostro DCF. Abbiamo fissato i parametri di Beta, Risk Free e Market Premium secondo le attuali condizioni del titolo e del mercato.

Si calcola il costo del debito (Rd), le disponibilità immediate o quasi (cash), il debito netto (D), il market cap (E). Infine calcoliamo il WACC assumendo una tassazione del 21% (attuale, USA).

3.Terminal Value

g<- mean(diff(log(rev(fcf))))

print(MSFT_WACC)
## [1] 0.08625623 0.08639758 0.08555045 0.08557851 0.08497682
print(g)
## [1] 0.1232938

Il nostro dividend growth rate, per questo caso specifico è più grande dei wacc calcolati. Per costruzione, la formula del TV di Gordon ha bisogno di una g inferiore al WACC. Per questa specifica situazione, useremo un g fisso pari alla media del settore di appartenenza

g<- 0.06

calculate_terminal_value <- function(df, g) {
  FCF_n <- fcf[1]
  WACC_n <- MSFT_WACC[1]

  if (WACC_n <= g) {
    warning(" WACC value is lower than g")
    return(NA)
  }
  
  TV <- (FCF_n * (1 + g)) / (WACC_n - g)
  return(TV)
}

MSFT_TV<- calculate_terminal_value(df,g)
print(MSFT_TV)
## [1] 2.990347e+12

4.Discounted Cash Flow

calculate_dcf <- function(fcf, WACC, TV) {
  n <- length(fcf)
  discounted_fcf <- fcf / (1 + WACC)^(1:n)
  discounted_TV <- TV / (1 + WACC)^n
  dcf_value <- sum(discounted_fcf) + discounted_TV
  return(dcf_value)
}

MSFT_DCF <- calculate_dcf(fcf, MSFT_WACC, MSFT_TV)
MSFT_DCF <- as.numeric(MSFT_DCF)
MSFT_MK <- as.numeric(key_metrics$marketCap)

if (length(MSFT_DCF) == length(MSFT_MK)) {
  for (i in 1:length(MSFT_DCF)) {
    if (MSFT_DCF[i] > MSFT_MK[i]) {
      cat("Anno", i, "→ Microsoft è SOTTOVALUTATA secondo il DCF!\n")
    } else {
      cat("Anno", i, "→ Microsoft è SOPRAVVALUTATA secondo il DCF!\n")
    }
  }
} else {
  cat(" Errore: I vettori non hanno la stessa lunghezza!\n")
}
## Anno 1 → Microsoft è SOPRAVVALUTATA secondo il DCF!
## Anno 2 → Microsoft è SOPRAVVALUTATA secondo il DCF!
## Anno 3 → Microsoft è SOTTOVALUTATA secondo il DCF!
## Anno 4 → Microsoft è SOTTOVALUTATA secondo il DCF!
## Anno 5 → Microsoft è SOTTOVALUTATA secondo il DCF!
df_MSFT <- data.frame(
  Anno = seq(from = 2024, by = -1, length.out = length(MSFT_DCF)),  
  MSFT_DCF = round(MSFT_DCF, 2),  
  MSFT_Market_Cap = round(MSFT_MK, 2),
  Valutazione = ifelse(MSFT_DCF > MSFT_MK, "SOTTOVALUTATA", "SOPRAVVALUTATA")  
)


print(df_MSFT)
##   Anno     MSFT_DCF MSFT_Market_Cap    Valutazione
## 1 2024 2.217246e+12    3.393961e+12 SOPRAVVALUTATA
## 2 2023 2.215960e+12    2.535661e+12 SOPRAVVALUTATA
## 3 2022 2.223682e+12    1.925198e+12  SOTTOVALUTATA
## 4 2021 2.223425e+12    2.044482e+12  SOTTOVALUTATA
## 5 2020 2.228931e+12    1.548711e+12  SOTTOVALUTATA

Ho voluto procedere step-by-by in questo processo di calcolo del DCF, a dimostrazione dell’elevata versatilità d’uso di questa API. Possiamo avere una valutazione DCF “end of the day” facendo una semplice chiamata:

DCF_MS<- FMP_CALL("discounted-cash-flow/MSFT")

print(DCF_MS)
##   symbol       date      dcf Stock Price
## 1   MSFT 2025-03-05 389.3409       396.5

Conclusioni

Avendo accesso ad un ampio database è possibile facilitare ed automatizzare grandi processi di valutazione e analisi finanziaria. L’utilizzo di API per ottenere più rapidamente determinati dati da server centralizzati è un potente strumento che assiste e velocizza il processo di analisi nel mondo finanziario. In questo progetto ho studiato la versatilità offerta dall’utilizzo dell’API di Financial Modelling Prep nell’analisi di diversi tipi di indicatori e valori, usandoli anche in ulteriori modellistiche esterne.

Questo studio può essere sicuramente ampliato ed applicato ad altri studi nell’ambito della finanza.

Appendice: Lista dei comandi v 1.0